package com.yykj.hospital.server.service.impl;

import com.yykj.base.client.dto.WordBriefInfo;
import com.yykj.base.client.feign.BaseFeignClient;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.util.LocalObjectUtil;
import com.yykj.hospital.client.dto.HospitalDepartmentDTO;
import com.yykj.hospital.client.dto.DepartmentListDTO;
import com.yykj.hospital.client.form.DepartmentEditForm;
import com.yykj.hospital.client.form.HotDepartmentEditForm;
import com.yykj.hospital.server.converter.DepartmentConverter;
import com.yykj.hospital.server.converter.HospitalDepartmentDTOConverter;
import com.yykj.hospital.server.form.HospitalDepartmentSearchFrom;
import com.yykj.hospital.server.model.entity.HospitalDepartment;
import com.yykj.hospital.server.model.repository.HospitalDepartmentRepository;
import com.yykj.hospital.server.service.DepartmentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * Created by chendg on 2021/9/9 0009.
 */
@Service
public class DepartmentServiceImpl implements DepartmentService {

    @Override
    public HospitalDepartmentDTO getDepartment(Integer id) {
        return DepartmentConverter.convert(findById(id));
    }

    @Override
    public HospitalDepartmentDTO editDepartment(DepartmentEditForm departmentEditForm) {
        if (departmentEditForm.getSorting() == null
                || departmentEditForm.getSorting() < 0) {
            departmentEditForm.setSorting(100);
        }
        if (departmentEditForm.getPid() == null || departmentEditForm.getPid() < 0) {
            departmentEditForm.setPid(0);
        }

        HospitalDepartment hospitalDepartment;

        HospitalDepartment oldDepartment = hospitalDepartmentRepository.findFirstByHospitalIdAndPidAndName(departmentEditForm.getHospitalId(), departmentEditForm.getPid(), departmentEditForm.getName());

        if (departmentEditForm.getId() != null && departmentEditForm.getId() > 0) {// 编辑
            hospitalDepartment = findById(departmentEditForm.getId());
            if (!oldDepartment.getId().equals(departmentEditForm.getId())) {
                throw new NormalException(ResultEnums.DEPARTMENT_NAME_EXIST_ERROR);
            }
            LocalObjectUtil.copyNullValue(departmentEditForm, hospitalDepartment);

        } else {// 新增
            hospitalDepartment = new HospitalDepartment();
            if (oldDepartment != null) {
                throw new NormalException(ResultEnums.DEPARTMENT_NAME_EXIST_ERROR);
            }
            BeanUtils.copyProperties(departmentEditForm, hospitalDepartment);
        }
        if (departmentEditForm.getName() != null) {
            WordBriefInfo wordBriefInfo = baseFeignClient.getWordBriefInfo(departmentEditForm.getName());
            hospitalDepartment.setPy(wordBriefInfo.getPy());
            hospitalDepartment.setWb(wordBriefInfo.getWb());
        }
        if (hospitalDepartment.getPid() == null) {
            hospitalDepartment.setPid(0);
        }
        if (hospitalDepartment.getHot() == null) {
            hospitalDepartment.setHot(false);
        }

        hospitalDepartmentRepository.save(hospitalDepartment);
        return DepartmentConverter.convert(hospitalDepartment);
    }

    @Override
    public void deleteDepartment(Integer id) {
        HospitalDepartment hospitalDepartment = findById(id);
        // TODO 删除逻辑
        hospitalDepartmentRepository.delete(hospitalDepartment);
    }

    @Override
    public List<DepartmentListDTO> getHospitalDepartment(HospitalDepartmentSearchFrom hospitalDepartmentSearchFrom) {
        List<DepartmentListDTO> result = new ArrayList<>();
        if (hospitalDepartmentSearchFrom.getHospitalId() == null) {
            throw new NormalException(ResultEnums.PARAM_ERROR);
        }
        if (hospitalDepartmentSearchFrom.getLevel() == null) {
            hospitalDepartmentSearchFrom.setLevel(0);
        }

        List<HospitalDepartment> list = hospitalDepartmentRepository.findAll(new Specification<HospitalDepartment>() {
            @Override
            public Predicate toPredicate(Root<HospitalDepartment> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

                List<Predicate> predicateList = new ArrayList<>();

                predicateList.add(criteriaBuilder.equal(root.get("hospitalId"), hospitalDepartmentSearchFrom.getHospitalId()));
                if (!StringUtils.isEmpty(hospitalDepartmentSearchFrom.getDepCode())) {
                    predicateList.add(criteriaBuilder.like(root.get("depCode"), "%" + hospitalDepartmentSearchFrom.getDepCode() + "%"));
                }

                if (hospitalDepartmentSearchFrom.getHot() != null) {
                    predicateList.add(criteriaBuilder.equal(root.get("hot"), hospitalDepartmentSearchFrom.getHot()));
                }

                if (!StringUtils.isEmpty(hospitalDepartmentSearchFrom.getName())) {
                    Predicate name = criteriaBuilder.like(root.get("name"), "%" + hospitalDepartmentSearchFrom.getName() + "%");
                    Predicate py = criteriaBuilder.like(root.get("py"), "%" + hospitalDepartmentSearchFrom.getName() + "%");
                    Predicate wb = criteriaBuilder.like(root.get("wb"), "%" + hospitalDepartmentSearchFrom.getName() + "%");

                    predicateList.add(criteriaBuilder.or(name, py, wb));
                }
                if (hospitalDepartmentSearchFrom.getLevel() != null && (hospitalDepartmentSearchFrom.getLevel() == 1 || hospitalDepartmentSearchFrom.getLevel() == 2)) {
                    if (hospitalDepartmentSearchFrom.getLevel() == 1) {
                        predicateList.add(criteriaBuilder.equal(root.get("pid"), 0));
                    }
                    if (hospitalDepartmentSearchFrom.getLevel() == 2) {
                        predicateList.add(criteriaBuilder.notEqual(root.get("pid"), 0));
                    }
                }
                if (hospitalDepartmentSearchFrom.getSorting() != null && hospitalDepartmentSearchFrom.getSorting() > 0) {
                    predicateList.add(criteriaBuilder.equal(root.get("sorting"), hospitalDepartmentSearchFrom.getSorting()));
                }
                Predicate[] predicateArray = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicateArray)).getRestriction();
            }
        });

        if (hospitalDepartmentSearchFrom.getLevel() == 2 && list.size() > 0) {
            Set<Integer> pidSet = new HashSet<>();
            for (HospitalDepartment hospitalDepartment : list) {
                pidSet.add(hospitalDepartment.getPid());
            }
            List<HospitalDepartment> pidDep = hospitalDepartmentRepository.findAllByHospitalIdAndIdIn(hospitalDepartmentSearchFrom.getHospitalId(), pidSet);
            list.addAll(pidDep);

        }

        for (HospitalDepartment hospitalDepartment : list) {
            if (hospitalDepartment.getPid() == 0) {
                DepartmentListDTO dto = new DepartmentListDTO();
                BeanUtils.copyProperties(hospitalDepartment, dto);
                for (HospitalDepartment child : list) {
                    if (hospitalDepartment.getId().equals(child.getPid())) {
                        dto.getList().add(DepartmentConverter.convert(child));
                    }
                }
                result.add(dto);
            }

        }
        return result;
    }

    @Override
    public HospitalDepartmentDTO editHotDepartment(HotDepartmentEditForm hotDepartmentEditForm) {
        HospitalDepartment department = findById(hotDepartmentEditForm.getId());
        if (!department.getHospitalId().equals(hotDepartmentEditForm.getHospitalId())) {
            throw new NormalException(ResultEnums.NOT_EXIST);
        }
        if (!StringUtils.isEmpty(hotDepartmentEditForm.getPic())) {
            department.setPic(hotDepartmentEditForm.getPic());
        }
        if (hotDepartmentEditForm.getSorting() != null && hotDepartmentEditForm.getSorting() >= 0) {
            department.setSorting(hotDepartmentEditForm.getSorting());
        }

        department.setHot(true);

        department = hospitalDepartmentRepository.save(department);
        return DepartmentConverter.convert(department);
    }

    @Override
    public List<HospitalDepartmentDTO> listHotDepartment(Integer hospitalId) {
        HospitalDepartmentSearchFrom build = HospitalDepartmentSearchFrom.builder()
                .hospitalId(hospitalId)
                .level(2)
                .hot(true)
                .build();
        List<DepartmentListDTO> hospitalDepartment = getHospitalDepartment(build);
        List<HospitalDepartmentDTO> list = new ArrayList<>();
        for (DepartmentListDTO dto : hospitalDepartment) {
            for (HospitalDepartmentDTO departmentDTO : dto.getList()) {
                if (list.size() < 12) {
                    list.add(departmentDTO);
                }
            }
        }
        return list;
    }

    @Override
    public void deleteHotDepartment(Integer id) {
        HospitalDepartment department = findById(id);
        department.setHot(Boolean.FALSE);
        hospitalDepartmentRepository.save(department);
    }

    @Override
    public List<HospitalDepartmentDTO> listBackstageHotDepartment(Integer hospitalId) {

        List<HospitalDepartmentDTO> result = new ArrayList<>();
        List<HospitalDepartment> departmentList = hospitalDepartmentRepository.findAllByHospitalId(hospitalId);

        for (HospitalDepartment department : departmentList) {
            if (Boolean.TRUE.equals(department.getHot())) {
                HospitalDepartmentDTO dto = new HospitalDepartmentDTO();
                BeanUtils.copyProperties(department, dto);
                if (department.getPid() != 0) {
                    dto.setDepIds(Arrays.asList(department.getPid(), department.getId()));
                }
                result.add(dto);
            }
        }
        return result;
    }

    private HospitalDepartment findById(Integer id) {
        return hospitalDepartmentRepository.findById(id)
                .orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
    }

    private BaseFeignClient baseFeignClient;

    private HospitalDepartmentRepository hospitalDepartmentRepository;

    @Autowired
    public void setDepartmentRepository(HospitalDepartmentRepository hospitalDepartmentRepository) {
        this.hospitalDepartmentRepository = hospitalDepartmentRepository;
    }

    @Autowired
    public void setBaseFeignClient(BaseFeignClient baseFeignClient) {
        this.baseFeignClient = baseFeignClient;
    }
}
